package com.niodata.dp.core.security;

import com.niodata.dp.core.OwnerType;
import com.niodata.dp.core.resource.ResourceDetail;
import com.niodata.dp.core.resource.ResourceMapper;
import com.niodata.dp.core.resource.ResourceType;
import com.niodata.dp.core.usermgr.dao.GroupInfoMapper;
import com.niodata.dp.core.usermgr.dao.UserGroupMapper;
import com.niodata.dp.core.usermgr.dao.UserInfoMapper;
import com.niodata.dp.core.usermgr.enums.GroupRole;
import com.niodata.dp.core.usermgr.model.GroupInfo;
import com.niodata.dp.core.usermgr.model.UserGroup;
import com.niodata.dp.core.usermgr.model.UserInfo;
import java.util.Date;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

@Component("ResourceSecurityManagerImpl")
public class ResourceSecurityManagerImpl implements ResourceSecurityManager {

  @Autowired
  private ResourceAuthMapper resourceAuthMapper;
  @Autowired
  private ResourceMapper resourceMapper;
  @Autowired
  private UserGroupMapper userGroupMapper;

  @Autowired
  private GroupInfoMapper groupMapper;

  @Autowired
  private UserInfoMapper userInfoMapper;

  @Override
  public void grantAccess(ResourceAuth resourceAuth) {
    this.resourceAuthMapper.addResAuth(resourceAuth);
  }

  @Override
  public void revokeAccess(ResourceAuth resourceAuth) {
    if (resourceAuth.getTargetType().equals(OwnerType.USER.name())) {
      resourceAuthMapper.deleteResAuth(resourceAuth.getResourceId(), resourceAuth.getTargetId(),
            OwnerType.USER.name(), resourceAuth.getAccessType());
    } else {
      resourceAuthMapper.deleteResAuth(resourceAuth.getResourceId(), resourceAuth.getTargetId(),
            OwnerType.GROUP.name(), resourceAuth.getAccessType());
    }
  }

  @Override
  @Transactional
  public void grantGroupAccess(String resId, long groupId, String accessType) {
    ResourceAuth resourceAuth = new ResourceAuth();
    ResourceDetail detail = resourceMapper.getResourceById(resId);
    resourceAuth.setAccessType(accessType);
    resourceAuth.setAuthTime(new Date());
    resourceAuth.setResourceId(resId);
    resourceAuth.setResPath(detail.getPath());
    resourceAuth.setResType(detail.getTypeName());
    resourceAuth.setTargetId(groupId);
    GroupInfo groupInfo = this.groupMapper.getGroupInfo(groupId);
    resourceAuth.setTargetName(groupInfo.getGroupName());
    resourceAuth.setTargetType(OwnerType.GROUP.name());
    resourceAuthMapper.addResAuth(resourceAuth);
  }

  @Override
  @Transactional
  public void grantGroupAccess(String resId, List<Long> groupIds, String accessType) {
    ResourceDetail detail = resourceMapper.getResourceById(resId);
    for (long groupId : groupIds) {
      ResourceAuth resourceAuth = new ResourceAuth();
      resourceAuth.setAccessType(accessType);
      resourceAuth.setAuthTime(new Date());
      resourceAuth.setResourceId(resId);
      resourceAuth.setResPath(detail.getPath());
      resourceAuth.setResType(detail.getTypeName());
      resourceAuth.setTargetId(groupId);
      GroupInfo groupInfo = this.groupMapper.getGroupInfo(groupId);
      resourceAuth.setTargetName(groupInfo.getGroupName());
      resourceAuth.setTargetType(OwnerType.GROUP.name());
      resourceAuthMapper.addResAuth(resourceAuth);
    }

  }

  @Transactional
  @Override
  public void grantUserAccess(String resId, long userId, String accessType) {
    ResourceDetail detail = resourceMapper.getResourceById(resId);
    ResourceAuth resourceAuth = new ResourceAuth();
    resourceAuth.setAccessType(accessType);
    resourceAuth.setAuthTime(new Date());
    resourceAuth.setResourceId(resId);
    resourceAuth.setResPath(detail.getPath());
    resourceAuth.setResType(detail.getTypeName());
    resourceAuth.setTargetId(userId);
    UserInfo userInfo = this.userInfoMapper.getUserInfo(userId);
    resourceAuth.setTargetName(userInfo.getUserName());
    resourceAuth.setTargetType(OwnerType.USER.name());
    resourceAuthMapper.addResAuth(resourceAuth);
  }

  @Override
  @Transactional
  public void grantUserAccess(String resId, List<Long> userIds, String accessType) {
    ResourceDetail detail = resourceMapper.getResourceById(resId);
    for (long userId : userIds) {
      ResourceAuth resourceAuth = new ResourceAuth();
      resourceAuth.setAccessType(accessType);
      resourceAuth.setAuthTime(new Date());
      resourceAuth.setResourceId(resId);
      resourceAuth.setResPath(detail.getPath());
      resourceAuth.setTargetId(userId);
      resourceAuth.setTargetType(OwnerType.USER.name());
      resourceAuth.setResType(detail.getTypeName());
      UserInfo userInfo = this.userInfoMapper.getUserInfo(userId);
      resourceAuth.setTargetName(userInfo.getUserName());
      resourceAuthMapper.addResAuth(resourceAuth);
    }
  }

  @Override
  @Transactional
  public void revokeGroupAccess(String resId, long groupId, String accessType) {
    resourceAuthMapper.deleteResAuth(resId, groupId, OwnerType.GROUP.name(), accessType);

  }

  @Override
  @Transactional
  public void revokeUserAccess(String resId, long userId, String accessType) {
    resourceAuthMapper.deleteResAuth(resId, userId, OwnerType.USER.name(), accessType);

  }

  @Override
  public void grantAccessToAnyUser(String resId, String accessType) {
    GroupInfo group = groupMapper.getGroupInfoByName("All");
    this.grantGroupAccess(resId, group.getGroupId(), accessType);
  }

  @Override
  public void revokeAccessFromAnyUser(String resId, String accessType) {
    resourceAuthMapper.deleteResAuth(resId, 0, null, null);
  }

  @Override
  public List<ResourceAuth> getGroupAuthorizedRes(long groupId, ResourceType resourceType) {
    return resourceAuthMapper.getResourceAuth(null, groupId, OwnerType.GROUP.name(),
          resourceType.getTypeName(), null);
  }

  @Override
  public List<ResourceAuth> getGroupAuthorizedRes(long groupId, ResourceType resourceType,
        String accessType) {
    return resourceAuthMapper.getResourceAuth(null, groupId, OwnerType.GROUP.name(),
          resourceType.getTypeName(), accessType);
  }

  @Override
  public List<ResourceAuth> getUserAuthorizedRes(long userId, ResourceType resourceType) {
    List<ResourceAuth> resourceAuths =
          resourceAuthMapper
                .getUserAuthorizedResourceAuth(resourceType.getTypeName(), userId, null);
    return resourceAuths;
  }

  @Override
  public List<ResourceAuth> getUserAuthorizedRes(long userId, ResourceType resourceType,
        String accessType) {
    List<ResourceAuth> resourceAuths =
          resourceAuthMapper
                .getUserAuthorizedResourceAuth(resourceType.getTypeName(), userId, accessType);
    return resourceAuths;
  }

  @Override
  public List<ResourceAuth> getUserResourceAuthOfResource(long userId, String resId) {
    return this.resourceAuthMapper
          .getResourceAuth(resId, userId, OwnerType.USER.name(), null, null);
  }

  @Override
  public List<ResourceAuth> getResAuthorizedTargets(String resId, String targetType) {
    return resourceAuthMapper.getResourceAuth(resId, 0, targetType, null, null);
  }

  @Override
  public List<ResourceAuth> getUseManagedResAuth(long userId, ResourceType resourceType,
        String targetType, String targetId, int offset,
        int count) {
    return this.resourceAuthMapper
          .getUserManagedResourceAuth(resourceType.getTypeName(), userId, targetType, targetId,
                offset, count);
  }

  @Override
  public boolean isResourceManagedByUser(long userId, String resId) {
    ResourceDetail detail = this.resourceMapper.getResourceById(resId);
    if (detail == null) {
      return false;
    }
    if (detail.getOwnerType().equals(OwnerType.GROUP)) {
      UserGroup userGroup = this.userGroupMapper.getUserGroup(userId, detail.getOwnerId());
      if (userGroup == null) {
        return false;
      }
      return userGroup.getRole().equals(GroupRole.MASTER)
            || userGroup.getRole().equals(GroupRole.OWNER);

    } else if (detail.getOwnerType().equals(OwnerType.USER)) {
      return detail.getOwnerId() == userId;
    }
    return false;
  }

}
